package oracle

import (
	"database/sql/driver"
	"fmt"
	"reflect"
	"strings"

	"github.com/pkg/errors"
)

func parseEntityTableInfo(entity interface{}) (*TableInfo, error) {
	// 取请求结构体
	et := reflect.TypeOf(entity)
	ev := reflect.ValueOf(entity)

	// 通过反射获取表名
	var tableName string
	if e, ok := entity.(TableName); ok {
		tableName = e.TableName()
	} else {
		return nil, errors.Errorf("获取 tableName failed")
	}

	if et.Kind() == reflect.Pointer {
		ev = ev.Elem()
	}

	v := ev
	f := v.Type()

	colNum := f.NumField()

	tbl := &TableInfo{
		TableName:    tableName,
		ColNum:       colNum,
		Columns:      make([]string, colNum),
		ColumnTypes:  make([]string, colNum),
		PlaceHolders: make([]string, colNum),
		Data:         make([]interface{}, colNum),
		ZeroFlag:     make([]bool, colNum),
		Scope:        make([]string, colNum),
	}

	// 遍历结构体
	idx := 0
	for i := 0; i < colNum; i++ {
		fv := v.Field(i)
		st := f.Field(i)

		if !fv.CanInterface() {
			return nil, errors.Errorf("[%s]Field is invalid!", st.Name)
		}
		tag, ok := parseTagName(&st)
		if !ok {
			continue
		}

		tbl.Columns[idx] = tag
		tbl.ColumnTypes[idx] = st.Type.String()
		tbl.PlaceHolders[idx] = fmt.Sprintf(":%s", tbl.Columns[idx])
		tbl.ZeroFlag[idx] = fv.IsZero()
		tbl.Scope[idx] = parseTagField(st.Tag, "scope")

		// Valuer
		value := fv.Interface()
		fieldType := reflect.TypeOf(value)
		if fieldType.Implements(reflect.TypeOf((*driver.Valuer)(nil)).Elem()) {
			tbl.Data[idx], _ = value.(driver.Valuer).Value()
		} else { // 普通
			tbl.Data[idx] = value
		}
		idx++
	}

	tbl.ColNum = idx
	tbl.Columns = tbl.Columns[:idx]
	tbl.ColumnTypes = tbl.ColumnTypes[:idx]
	tbl.PlaceHolders = tbl.PlaceHolders[:idx]
	tbl.Data = tbl.Data[:idx]
	tbl.ZeroFlag = tbl.ZeroFlag[:idx]
	tbl.Scope = tbl.Scope[:idx]

	return tbl, nil
}

func parseEntity2Columns(entity interface{}, columns []string) []interface{} {
	ev := reflect.ValueOf(entity)

	if ev.Kind() != reflect.Pointer {
		return nil
	}
	v := ev.Elem()
	f := v.Type()

	parseStruct := func() map[string]interface{} {
		colNum := v.NumField()
		data := make(map[string]interface{}, 0)
		// 遍历结构体
		for i := 0; i < colNum; i++ {
			fv := v.Field(i)
			st := f.Field(i)

			if !fv.CanInterface() {
				return nil
			}

			tag, ok := parseTagName(&st)
			if !ok {
				continue
			}

			// 获取TAG名称
			data[tag] = fv.Addr().Interface()
		}
		return data
	}

	data := parseStruct()

	var valueList []interface{}
	for _, c := range columns {
		if _, ok := data[c]; ok {
			valueList = append(valueList, data[c])
		} else { // 忽略掉
			var v interface{}
			valueList = append(valueList, &v)
		}
	}

	return valueList
}

func parseEntity2ColumnsV1(entity interface{}) []interface{} {
	ev := reflect.ValueOf(entity)

	if ev.Kind() != reflect.Pointer {
		return nil
	}
	v := ev.Elem()
	f := v.Type()

	parseStruct := func() []interface{} {
		colNum := v.NumField()
		data := make([]interface{}, 0)
		// 遍历结构体
		for i := 0; i < colNum; i++ {
			fv := v.Field(i)
			st := f.Field(i)

			if !fv.CanInterface() {
				return nil
			}

			_, ok := parseTagName(&st)
			if !ok {
				continue
			}
			// 获取TAG名称
			data = append(data, fv.Addr().Interface())
		}
		return data
	}

	return parseStruct()
}

const omitFlag = "-"

func parseTagName(st *reflect.StructField) (string, bool) {
	if v := st.Tag.Get("db"); v != "" {
		if tagName := strings.Split(v, ",")[0]; tagName == "" || tagName == omitFlag {
			return "", false
		} else {
			return tagName, true
		}
	}
	return "", false
}
